from itertools import groupby

from odoo import api, fields, models, tools, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import UserError
from odoo.tools.safe_eval import safe_eval


class SbMoScrapReport(models.Model):
    _name = 's.mo.scrap.report'
    _description = "Mo Scrap Report"
    _auto = False

    type = fields.Selection([
        ('sale', 'Sale'),
        ('rd', 'Research And Development')
    ], string='Type')
    invoice_number = fields.Char(string='Invoice Number')
    res_id = fields.Integer(string='Related Id')
    product_id = fields.Many2one('product.product', string='Product')
    scrap_qty = fields.Float(string='Scrap Qty(PCS)')
    real_scrap_qty = fields.Float(string='Scrap Qty(PCS)', compute='_compute_sub_scrap_qty', search='_search_real_scrap_qty')
    sub_scrap_qty = fields.Float(string='Child Scrap Qty(PCS)', compute='_compute_sub_scrap_qty', search='_search_sub_scrap_qty')
    production_ids = fields.Char(string='Mrp Productions')

    @api.depends('production_ids')
    def _compute_sub_scrap_qty(self):
        for rec in self:
            production_ids = list(set(safe_eval(rec.production_ids)))
            child_productions = self.env['mrp.production']
            for production_id in production_ids:
                production = self.env['mrp.production'].browse(production_id)
                child_productions |= production._get_all_child()
            child_productions = child_productions.filtered(lambda x: x.state != 'cancel')
            sub_scrap_qty = sum(child_productions.mapped('qty_reject')) if child_productions else 0
            # 计算已补料部分
            if rec.type == 'sale':
                supplement_lines = self.env['s.supplement.mo.detail'].search([
                    ('sale_order_line', '=', rec.res_id),
                    ('origin_mrp_production', 'in', production_ids)
                ])
                supplement_mrp_production = supplement_lines.supplement_mrp_production
                supplement_qty = sum(supplement_mrp_production.mapped('product_qty')) if supplement_mrp_production else 0
                rec.real_scrap_qty = rec.scrap_qty - supplement_qty

                sub_supplement_lines = self.env['s.supplement.mo.detail'].search([
                    ('sale_order_line', '=', rec.res_id),
                    ('origin_mrp_production', 'in', child_productions.ids)
                ])
                sub_supplement_mrp_production = sub_supplement_lines.supplement_mrp_production
                sub_supplement_qty = sum(sub_supplement_mrp_production.mapped('product_qty')) if sub_supplement_mrp_production else 0
                rec.sub_scrap_qty = sub_scrap_qty - sub_supplement_qty
            else:
                supplement_lines = self.env['s.supplement.mo.detail'].search([
                    ('development_line', '=', rec.res_id),
                    ('origin_mrp_production', 'in', production_ids)
                ])
                supplement_mrp_production = supplement_lines.supplement_mrp_production
                supplement_qty = sum(
                    supplement_mrp_production.mapped('product_qty')) if supplement_mrp_production else 0
                rec.real_scrap_qty = rec.scrap_qty - supplement_qty

                sub_supplement_lines = self.env['s.supplement.mo.detail'].search([
                    ('development_line', '=', rec.res_id),
                    ('origin_mrp_production', 'in', child_productions.ids)
                ])
                sub_supplement_mrp_production = sub_supplement_lines.supplement_mrp_production
                sub_supplement_qty = sum(sub_supplement_mrp_production.mapped('product_qty')) if sub_supplement_mrp_production else 0
                rec.sub_scrap_qty = sub_scrap_qty - sub_supplement_qty

    @api.model
    def _search_real_scrap_qty(self, operator, value):
        if operator not in ['=', '!=', '<', '>'] or not isinstance(value, int):
            raise UserError(_('Operation not supported.'))
        scrap_models = self.env['s.mo.scrap.report'].search([])
        if operator == '=':
            scrap_models = scrap_models.filtered(lambda m: m.real_scrap_qty == value)
        elif operator == '!=':
            scrap_models = scrap_models.filtered(lambda m: m.real_scrap_qty != value)
        elif operator == '<':
            scrap_models = scrap_models.filtered(lambda m: m.real_scrap_qty < value)
        elif operator == '>':
            scrap_models = scrap_models.filtered(lambda m: m.real_scrap_qty > value)
        return [('id', 'in', scrap_models.ids)]

    @api.model
    def _search_sub_scrap_qty(self, operator, value):
        if operator not in ['=', '!=', '<', '>'] or not isinstance(value, int):
            raise UserError(_('Operation not supported.'))
        scrap_models = self.env['s.mo.scrap.report'].search([])
        if operator == '=':
            scrap_models = scrap_models.filtered(lambda m: m.sub_scrap_qty == value)
        elif operator == '!=':
            scrap_models = scrap_models.filtered(lambda m: m.sub_scrap_qty != value)
        elif operator == '<':
            scrap_models = scrap_models.filtered(lambda m: m.sub_scrap_qty < value)
        elif operator == '>':
            scrap_models = scrap_models.filtered(lambda m: m.sub_scrap_qty > value)
        return [('id', 'in', scrap_models.ids)]

    def action_feeding(self):
        type_list = list(set(self.mapped('type')))
        if len(type_list) != 1:
            raise UserError('The type needs to be consistent')
        type = type_list[0]
        res_ids = self.mapped('res_id')
        scrap_qty = sum(self.mapped('scrap_qty'))
        if type == 'sale':
            return self.env['sale.order.line'].browse(res_ids).with_context({
                'mo_type': 'M',
                'res_model': 'sale.order.line',
                'res_ids': res_ids,
                'scrap_qty': scrap_qty,
            }).action_select_sale_to_wizard()
        else:
            return self.env['s.research.and.development.order.line'].browse(res_ids).with_context({
                'mo_type': 'M',
                'res_model': 's.research.and.development.order.line',
                'res_ids': res_ids,
                'scrap_qty': scrap_qty
            }).action_feeding()

    def init(self):
        tools.drop_view_if_exists(self.env.cr, self._table)
        self._cr.execute('''CREATE or REPLACE VIEW %s AS (
                with mp_scrap as (
                select 
                'sale' as type,
                so.name as invoice_number,
                sol.id as res_id,
                sol.product_id as product_id,
                sum(mw.qty_op_reject) as scrap_qty,
                string_agg(mo.id::TEXT, ',') as production_ids
                from 
                mrp_workorder mw 
                left join mrp_production mo on mo.id = mw.production_id
                left join mrp_production_sale_order_line_rel ms on ms.mrp_production_id = mo.id
                left join sale_order_line sol on sol.id = ms.sale_order_line_id
                left join sale_order so on so.id = sol.order_id 
                where mo.id in (select mrp_production_id from mrp_production_sale_order_line_rel)
                and mo.state != 'cancel'
                group by so.name, sol.id, sol.product_id
                
                union all 
                
                select 
                'rd' as type,
                rd.name as invoice_number,
                rdl.id as res_id,
                rdl.product_id as product_id,
                sum(mw.qty_op_reject) as scrap_qty,
                string_agg(mo.id::TEXT, ',') as production_ids
                from 
                mrp_workorder mw 
                left join mrp_production mo on mo.id = mw.production_id
                left join mrp_production_s_research_and_development_order_line_rel ms on ms.mrp_production_id = mo.id
                left join s_research_and_development_order_line rdl on rdl.id = ms.s_research_and_development_order_line_id
                left join s_research_and_development_order rd on rd.id = rdl.order_id 
                where mo.id in (select mrp_production_id from mrp_production_s_research_and_development_order_line_rel)
                and mo.state != 'cancel'
                group by rd.name, rdl.id, rdl.product_id
                )
                select 
                row_number() OVER() AS id,
                msc.type,
                msc.invoice_number,
                msc.res_id,
                msc.product_id,
                msc.production_ids as production_ids,
                msc.scrap_qty
                from mp_scrap msc
            )
            ''' % self._table)
